
import os
import subprocess
import pexpect
import gtk
import gtk.glade
import gobject
import pango
import time
import re
import datetime
from BuildWizException import BuildWizException
from DlgFileSelection import DlgFileSelection


class OutputWindow:
    def __init__( self, gladeFile, name, wizard):
        if not os.path.isfile( gladeFile):
            raise BuildWizException( "OutputWindow: libglade could not open - [%s]" % gladeFile)
        self.__glade = gladeFile
        self.__name = name
        self.__warn2Output = {}
        self.__report = {}
        self.__wiz = wizard
        self.__deployInfo = None
        self.__xml = gtk.glade.XML( self.__glade)
        if self.__xml:
            self.__win = self.__xml.get_widget( "OutputWindow")
            self.__winTitle = self.__name + " - build output"
            self.__win.set_title( self.__winTitle)
            #self.__win.hide()
            self.__entryPlatform = self.__xml.get_widget( "entryPlatform")
            self.__entryPlatform.set_text( self.__name)
            self.__outputView = self.__xml.get_widget( "txtvwOutput")
            self.__buffer = self.__outputView.get_buffer()
            self.__setFont( self.__wiz.getFontOutput( name)) 
            self.__setTextTags()
            self.__mark = self.__buffer.create_mark( "end", self.__buffer.get_end_iter(), False)

            # This MUST BE "delete-event" instead of "destroy" otherwise the
            # next time you try to show the window its internal widget will 
            # not be showed at all - (empty window)
            self.__win.connect( "delete-event", self.close)
            self.__handlers = { "on_btnClose_clicked": self.onBtnClose
                            , "on_btnSaveOutput_clicked": self.onBtnSave
                            , "on_btnStop_clicked": self.onBtnStop 
                            , "on_togglebtnDeploy_toggled": self.__onDeploy
                            , "on_btnFont_clicked": self.__onFontSelection
                            , "on_treeviewWarn_button_press_event": self.__onWarningBtnPressEvent
                            , "on_treeviewWarn_row_activated": self.__onWarningSelected }
            self.__xml.signal_autoconnect( self.__handlers)
            self.__btnStop = self.__xml.get_widget( "btnStop")
            self.__btnStop.set_sensitive( True)
            self.__btnSave = self.__xml.get_widget( "btnSaveOutput")
            self.__btnSave.set_sensitive( False)
            self.__btnDeploy = self.__xml.get_widget( "togglebtnDeploy")
            self.__setBtnDeploy()
            self.__btnFontSelection = self.__xml.get_widget( "btnFont")

            self.__treeviewWarn = self.__xml.get_widget( "treeviewWarn")
            self.__storeWarn = gtk.TreeStore( str)
            self.__treeviewWarn.set_model( self.__storeWarn)
            rendererWarn = gtk.CellRendererText()
            rendererWarn.set_property( 'editable', False)
            columnWarn = gtk.TreeViewColumn( "", rendererWarn, text=0)
            self.__treeviewWarn.append_column( columnWarn)

            self.__txtViewReport = self.__xml.get_widget( "textviewReport")
            self.__bufReport = self.__txtViewReport.get_buffer()
            self.__markReport = self.__bufReport.create_mark( "end", self.__bufReport.get_end_iter(), False)

            self.__vpaned = self.__xml.get_widget( "vpaned")
            self.__vpaned.set_position( 530)

            self.__report[ "elapsedTime"] = "00:00:00"
            self.__report[ "compiled"] = 0
            self.__report[ "warnings"] = 0


    def __setTextTags( self):
        self.__tagTable = self.__buffer.get_tag_table()

        self.__txtTagNormal = gtk.TextTag( "txtNormal")
        self.__txtTagNormal.set_property( "font-desc", self.__fontDesc)
        self.__txtTagNormal.set_property( "font", "regular")
        self.__tagTable.add( self.__txtTagNormal)

        self.__txtTagLinking = gtk.TextTag( "txtLinking")
        self.__txtTagLinking.set_property( "font-desc", self.__fontDesc)
        self.__txtTagLinking.set_property( "font", "bold")
        self.__txtTagLinking.set_property( "foreground", "red")
        self.__tagTable.add( self.__txtTagLinking)

        self.__txtTagScanning = gtk.TextTag( "txtScanning")
        self.__txtTagScanning.set_property( "font-desc", self.__fontDesc)
        self.__txtTagScanning.set_property( "font", "bold")
        self.__txtTagScanning.set_property( "foreground", "#ED09C0")
        self.__tagTable.add( self.__txtTagScanning)

        self.__txtTagWarning = gtk.TextTag( "txtWarning")
        self.__txtTagWarning.set_property( "font-desc", self.__fontDesc)
        self.__txtTagWarning.set_property( "font", "regular")
        self.__txtTagWarning.set_property( "foreground", "#7A29DD")
        self.__tagTable.add( self.__txtTagWarning)

        self.__txtTagBuilding = gtk.TextTag( "txtBuilding")
        self.__txtTagBuilding.set_property( "font-desc", self.__fontDesc)
        #self.__txtTagBuilding.set_property( "font", "bold")
        self.__txtTagBuilding.set_property( "foreground", "#118B1C")
        self.__tagTable.add( self.__txtTagBuilding)



    def generateReport( self):
        elapsedTime = "Build duration: [%s]\n" % (self.__report[ "elapsedTime"])
        start, end = self.__bufReport.get_bounds()
        self.__bufReport.insert_at_cursor( elapsedTime)
        self.__txtViewReport.scroll_to_mark( self.__markReport, 0.05, True, 0.0, 1.0)

        compiled = "Files compiled: [%d]\n" % (self.__report[ "compiled"])
        start, end = self.__bufReport.get_bounds()
        self.__bufReport.insert_at_cursor( compiled)
        self.__txtViewReport.scroll_to_mark( self.__markReport, 0.05, True, 0.0, 1.0)

        warnings = "Number of warnings: [%d]\n" % (self.__report[ "warnings"])
        start, end = self.__bufReport.get_bounds()
        self.__bufReport.insert_at_cursor( warnings)
        self.__txtViewReport.scroll_to_mark( self.__markReport, 0.05, True, 0.0, 1.0)


    def __clearReport( self):
        self.__report[ "compiled"] = 0
        self.__report[ "warnings"] = 0
        start, end = self.__bufReport.get_bounds()
        self.__bufReport.delete( start, end)


    def __getTxtTag( self, line):
        m = re.search( "^\[(...)%\]", line)
        if m:
            progress = m.group( 1)
            self.__win.set_title( self.__winTitle + " - " + progress + "%")
            self.__report[ "compiled"] = self.__report[ "compiled"] + 1
            return "txtBuilding"

        m = re.search( ": warning:", line)
        if m:
            self.__insertWarning( self.__buffer.get_end_iter(), line.rstrip( "\n"))
            self.__report[ "warnings"] = self.__report[ "warnings"] + 1
            return "txtWarning"

        m = re.search( "^Linking", line)
        if m:
            return "txtLinking"

        m = re.search( "^Scanning dependencies", line)
        if m:
            return "txtScanning"

        return "txtNormal"

    
    def __onWarningBtnPressEvent( self, warnView, event):
        if event.button == 1:
            pass
        elif event.button == 2:
            pass
        if event.button == 3:
            platfname = ""
            popup = gtk.Menu()
            popupOpenEditor = gtk.MenuItem( "Open editor for this warning")
            popup.append( popupOpenEditor)
            popupOpenEditor.show()
            x = int(event.x)
            y = int(event.y)
            time = event.time
            pthinfo = warnView.get_path_at_pos(x, y)
            if pthinfo is not None:
                selection = warnView.get_selection()
                path, col, cellx, celly = pthinfo

                # This line is necessary cos the rigth-click doesn't 
                # set 'iter' for the first time after calling 'get_selected()'
                selection.select_path( path)
                model, modelIt = selection.get_selected()
                warnLine = model[ path][ 0]
                warnView.grab_focus()
                warnView.set_cursor( path, col, 0)
                type( modelIt)
                popupOpenEditor.connect_object( "activate", self.__openEditor, warnLine, path[ 0])
                popup.popup( None, None, None, event.button, time)

    def __openEditor( self, warnLine, warnIdx):
        lineSplited = warnLine.split( ':')
        cmd = "gedit +" + lineSplited[ 1] + " " + lineSplited[ 0]
        try:
            child = pexpect.spawn( cmd, timeout=2)
            i = child.expect( ["", pexpect.EOF]) #, pexpect.TIMEOUT])
            if i == 1:        
                pass

        except pexpect.ExceptionPexpect, e:
            msg = "command: [%s]\nERROR: %s" % (cmd, e)
            dlg = gtk.MessageDialog( None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg)
            dlg.run()
            dlg.destroy()



    def __onWarningSelected( self, warnView, path, column):
        #model = warnView.get_model()
        #if self.__warn2Output.has_key( path[ 0]):
        #    pass
        #print path[0]
        #print model[ path][ 0]
        return True

    def __insertWarning( self, buffIt, line):
        treeIt = self.__storeWarn.append( None, [line])
        self.__warn2Output[ treeIt] = buffIt


    def __setFont( self, fontdescr):
        if fontdescr == "":
            fontdescr = "Monospace 9"

        self.__fontDesc = pango.FontDescription( fontdescr)
        self.__outputView.modify_font( self.__fontDesc)

    def isSensitive( self):
        return self.__win.get_property( "visible")

    def show( self):
        self.__win.deiconify()
        self.__win.show_all()
        return True # this is very important to show it right

    def clear( self):
        start = self.__buffer.get_start_iter()
        end = self.__buffer.get_end_iter()
        self.__buffer.delete( start, end)
        self.__btnStop.set_sensitive( True)
        self.__setBtnDeploy()
        self.__clearReport()
        self.__storeWarn.clear()

    def appendText( self, text):
        start, end = self.__buffer.get_bounds()
        txtTag = self.__getTxtTag( text)
        if txtTag == "txtBuilding":
            self.__buffer.insert_with_tags_by_name( end, text[0:6], "txtNormal" )
            self.__buffer.insert_with_tags_by_name( end, text[6:], "txtBuilding" )
        else:
            self.__buffer.insert_with_tags_by_name( end, text, txtTag)
        
        self.__outputView.scroll_to_mark( self.__mark, 0.05, True, 0.0, 1.0)

    def close( self, widget, ev=None):
        self.__win.iconify()
        return True # this is very important to show it right

    def destroy( self):
        self.__win.hide()
        self.__win.destroy()

    def onBtnClose( self, button):
        self.close( button)

    def __printStopMessage( self):
        time.sleep( 1.5)
        self.appendText( "\n=*=*= TERMINATED BY THE USER! =*=*=\n")

    def notifyOuterStop( self):
        self.__printStopMessage()
        self.__btnStop.set_sensitive( False)

    def onBtnStop( self, button):
        self.__wiz.stopBuilder( self.__name)
        self.__printStopMessage()
        self.__btnStop.set_sensitive( False)

    def onBtnSave( self, button):
        start = self.__buffer.get_start_iter()
        end = self.__buffer.get_end_iter()
        text = self.__buffer.get_text( start, end)
        now = datetime.datetime.now()
        filename = self.__name + "-output-" + now.strftime("%Y%m%d%H%M%S") + ".out"
        dlg = DlgFileSelection( "Save output", filename)
        dlg.show()
        try:
            out = open( dlg.getFileName(), "w")
            out.write( text)
            out.close()
        except IOError:
            pass

    def __onDeploy( self, btn):
        if self.__btnDeploy.get_active():
            self.__btnDeploy.set_label( "Deploy ON")
        else:
            self.__btnDeploy.set_label( "Deploy OFF")

    def isBtnDeployActivated( self):
        return self.__btnDeploy.get_active()

    def __onFontSelection( self, btn):
        dlg = gtk.FontSelectionDialog( "Font selection dialog")
        response = dlg.run()
        dlg.destroy()
        if response == gtk.RESPONSE_OK:
            fontdesc = dlg.get_font_name()
            if fontdesc:
                self.__setFont( fontdesc)
                self.__wiz.setFontOutput( self.__name, fontdesc)

    def __setBtnDeploy( self):
        self.__deployInfo = self.__wiz.getDeployInfo( self.__name)
        if len( self.__deployInfo) == 0:
            self.__btnDeploy.set_label( "Deploy OFF")
            self.__btnDeploy.set_active( False)
        else:
            if self.__deployInfo.has_key( "pen"):
                penInfo = self.__deployInfo[ "pen"]
                if penInfo.has_key( "deploy_after_build_process"):
                    if penInfo[ "deploy_after_build_process"]:
                        self.__btnDeploy.set_label( "Deploy ON")
                        self.__btnDeploy.set_active( True)
                    else:
                        self.__btnDeploy.set_label( "Deploy OFF")
                        self.__btnDeploy.set_active( False)

    def disableBtnStop( self):
        self.__btnStop.set_sensitive( False)

    def enableBtnSave( self):
        self.__btnSave.set_sensitive( True)

